---
title: "函數式程式設計特性"
description: "學習 Kotlin 的函數式程式設計特性，包括高階函數、Lambda 表達式、集合操作符和函數式程式設計模式"
---

# 函數式程式設計特性

歡迎來到 JavaScript 到 Kotlin 轉換的第三個模組！在本模組中，我們將探索 Kotlin 強大的函數式程式設計特性，以及它們與 JavaScript 函數式程式設計能力的對比。

## 學習目標

通過本模組的學習，您將能夠：
- 理解 Kotlin 的函數式程式設計範式
- 有效使用高階函數
- 使用 Lambda 表達式和函數類型
- 掌握集合操作符和函數式操作
- 創建擴展函數
- 應用函數式程式設計模式
- 對比 Kotlin 和 JavaScript 的函數式特性

## 理解 Kotlin 中的函數式程式設計

### 什麼是函數式程式設計？

函數式程式設計是一種程式設計範式，它將計算視為數學函數的求值，避免改變狀態和可變數據。Kotlin 在保持面向對象能力的同時，為函數式程式設計提供了出色的支持。

<UniversalEditor title="函數式程式設計對比" compare={true}>
```javascript !! js
// JavaScript 函數式程式設計
const numbers = [1, 2, 3, 4, 5];

// 帶回調的高階函數
const doubled = numbers.map(num => num * 2);
const filtered = numbers.filter(num => num % 2 === 0);
const sum = numbers.reduce((acc, num) => acc + num, 0);

// 函數組合
const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x);
const addOne = x => x + 1;
const multiplyByTwo = x => x * 2;
const process = compose(addOne, multiplyByTwo);
```

```kotlin !! kt
// Kotlin 函數式程式設計
val numbers = listOf(1, 2, 3, 4, 5)

// 帶 Lambda 表達式的高階函數
val doubled = numbers.map { it * 2 }
val filtered = numbers.filter { it % 2 == 0 }
val sum = numbers.reduce { acc, num -> acc + num }

// 函數組合
fun <T> compose(vararg functions: (T) -> T): (T) -> T = 
    { x -> functions.foldRight(x) { fn, acc -> fn(acc) } }

val addOne: (Int) -> Int = { it + 1 }
val multiplyByTwo: (Int) -> Int = { it * 2 }
val process = compose(addOne, multiplyByTwo)
```
</UniversalEditor>

### Kotlin 函數式程式設計的優勢

1. **類型安全**: 強類型系統防止運行時錯誤
2. **空安全**: 內建空安全減少空指針異常
3. **不可變性**: 預設不可變集合
4. **擴展函數**: 無需繼承即可擴展現有類
5. **Lambda 表達式**: 匿名函數的簡潔語法
6. **高階函數**: 接受或返回函數的函數

## 高階函數

### 理解高階函數

高階函數是接受其他函數作為參數或返回函數作為結果的函數。Kotlin 使這個概念非常自然且類型安全。

<UniversalEditor title="高階函數" compare={true}>
```javascript !! js
// JavaScript 高階函數
function applyOperation(numbers, operation) {
    return numbers.map(operation);
}

function createMultiplier(factor) {
    return function(number) {
        return number * factor;
    };
}

// 使用
const numbers = [1, 2, 3, 4, 5];
const doubled = applyOperation(numbers, x => x * 2);
const tripler = createMultiplier(3);
const tripled = applyOperation(numbers, tripler);
```

```kotlin !! kt
// Kotlin 高階函數
fun applyOperation(numbers: List<Int>, operation: (Int) -> Int): List<Int> {
    return numbers.map(operation)
}

fun createMultiplier(factor: Int): (Int) -> Int {
    return { number -> number * factor }
}

// 使用
val numbers = listOf(1, 2, 3, 4, 5)
val doubled = applyOperation(numbers) { it * 2 }
val tripler = createMultiplier(3)
val tripled = applyOperation(numbers, tripler)
```
</UniversalEditor>

### Kotlin 中的函數類型

Kotlin 擁有豐富的函數類型系統，使高階函數更具表現力和類型安全。

<UniversalEditor title="函數類型" compare={true}>
```javascript !! js
// JavaScript 函數類型（非正式）
// 函數是一等公民但沒有顯式類型系統
function processData(data, processor) {
    return processor(data);
}

function stringProcessor(str) {
    return str.toUpperCase();
}

function numberProcessor(num) {
    return num * 2;
}

// 使用 - 編譯時沒有類型檢查
const result1 = processData("hello", stringProcessor);
const result2 = processData(5, numberProcessor);
```

```kotlin !! kt
// Kotlin 函數類型，具有顯式類型安全
fun processData(data: String, processor: (String) -> String): String {
    return processor(data)
}

fun processNumber(data: Int, processor: (Int) -> Int): Int {
    return processor(data)
}

val stringProcessor: (String) -> String = { it.uppercase() }
val numberProcessor: (Int) -> Int = { it * 2 }

// 使用 - 編譯時類型安全
val result1 = processData("hello", stringProcessor)
val result2 = processNumber(5, numberProcessor)
```
</UniversalEditor>

## Lambda 表達式

### Lambda 語法

Kotlin 中的 Lambda 表達式提供了一種創建匿名函數的簡潔方式。語法比 JavaScript 的箭頭函數在許多情況下更簡潔。

<UniversalEditor title="Lambda 表達式" compare={true}>
```javascript !! js
// JavaScript 箭頭函數
const numbers = [1, 2, 3, 4, 5];

// 單個參數
const doubled = numbers.map(num => num * 2);

// 多個參數
const sum = numbers.reduce((acc, num) => acc + num, 0);

// 無參數
const getRandom = () => Math.random();

// 多個語句
const processNumber = num => {
    const doubled = num * 2;
    return doubled > 5 ? doubled : 0;
};
```

```kotlin !! kt
// Kotlin Lambda 表達式
val numbers = listOf(1, 2, 3, 4, 5)

// 單個參數（it 是隱式參數）
val doubled = numbers.map { it * 2 }

// 多個參數
val sum = numbers.reduce { acc, num -> acc + num }

// 無參數
val getRandom = { kotlin.random.Random.nextDouble() }

// 多個語句
val processNumber = { num: Int ->
    val doubled = num * 2
    if (doubled > 5) doubled else 0
}
```
</UniversalEditor>

### 帶接收者的 Lambda

Kotlin 的帶接收者的 Lambda 是一個強大的特性，允許您在 Lambda 作用域內調用對象的方法。

<UniversalEditor title="帶接收者的 Lambda" compare={true}>
```javascript !! js
// JavaScript - 沒有直接等價物，但類似模式
function withObject(obj, callback) {
    return callback.call(obj);
}

const person = {
    name: "John",
    age: 30,
    greet() {
        return `Hello, I'm ${this.name}`;
    }
};

const result = withObject(person, function() {
    return this.greet();
});
```

```kotlin !! kt
// Kotlin 帶接收者的 Lambda
data class Person(val name: String, val age: Int) {
    fun greet() = "Hello, I'm $name"
}

val person = Person("John", 30)

// 帶接收者的 Lambda
val result = person.run {
    greet()
}

// 或使用 with 函數
val result2 = with(person) {
    greet()
}
```
</UniversalEditor>

## 集合操作符

### 函數式集合操作

Kotlin 標準庫提供了豐富的集合函數操作符，類似於 JavaScript 的數組方法，但具有更好的類型安全。

<UniversalEditor title="集合操作符" compare={true}>
```javascript !! js
// JavaScript 數組方法
const numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// 轉換
const doubled = numbers.map(x => x * 2);

// 過濾
const evens = numbers.filter(x => x % 2 === 0);

// 歸約
const sum = numbers.reduce((acc, x) => acc + x, 0);

// 鏈式操作
const result = numbers
    .filter(x => x > 5)
    .map(x => x * 2)
    .reduce((acc, x) => acc + x, 0);

// 查找
const firstEven = numbers.find(x => x % 2 === 0);

// 任意/全部
const hasEven = numbers.some(x => x % 2 === 0);
const allEven = numbers.every(x => x % 2 === 0);
```

```kotlin !! kt
// Kotlin 集合操作符
val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

// 轉換
val doubled = numbers.map { it * 2 }

// 過濾
val evens = numbers.filter { it % 2 == 0 }

// 歸約
val sum = numbers.reduce { acc, x -> acc + x }

// 鏈式操作
val result = numbers
    .filter { it > 5 }
    .map { it * 2 }
    .reduce { acc, x -> acc + x }

// 查找
val firstEven = numbers.find { it % 2 == 0 }

// 任意/全部
val hasEven = numbers.any { it % 2 == 0 }
val allEven = numbers.all { it % 2 == 0 }
```
</UniversalEditor>

### 高級集合操作

Kotlin 提供了超越 JavaScript 能力的高級集合操作。

<UniversalEditor title="高級集合操作" compare={true}>
```javascript !! js
// JavaScript - 一些高級操作
const numbers = [1, 2, 3, 4, 5];

// 分組
const grouped = numbers.reduce((acc, num) => {
    const key = num % 2 === 0 ? 'even' : 'odd';
    if (!acc[key]) acc[key] = [];
    acc[key].push(num);
    return acc;
}, {});

// 分區（自定義實現）
const partition = numbers.reduce((acc, num) => {
    if (num > 3) {
        acc.first.push(num);
    } else {
        acc.second.push(num);
    }
    return acc;
}, { first: [], second: [] });

// 扁平化
const nested = [[1, 2], [3, 4], [5]];
const flattened = nested.flat();
```

```kotlin !! kt
// Kotlin 高級集合操作
val numbers = listOf(1, 2, 3, 4, 5)

// 分組
val grouped = numbers.groupBy { if (it % 2 == 0) "even" else "odd" }

// 分區
val (greaterThan3, lessThanOrEqual3) = numbers.partition { it > 3 }

// 扁平化
val nested = listOf(listOf(1, 2), listOf(3, 4), listOf(5))
val flattened = nested.flatten()

// 壓縮
val names = listOf("Alice", "Bob", "Charlie")
val ages = listOf(25, 30, 35)
val people = names.zip(ages) { name, age -> "$name is $age years old" }

// 窗口
val windows = numbers.windowed(3, 1, true)
```
</UniversalEditor>

## 擴展函數

### 理解擴展函數

擴展函數是 Kotlin 最強大的特性之一，允許您向現有類添加新函數，而無需繼承或修改原始類。

<UniversalEditor title="擴展函數" compare={true}>
```javascript !! js
// JavaScript - 擴展對象（原型污染）
// 在現代 JavaScript 中不推薦
Array.prototype.double = function() {
    return this.map(x => x * 2);
};

// 或使用工具函數
function doubleArray(arr) {
    return arr.map(x => x * 2);
}

// 使用
const numbers = [1, 2, 3];
const doubled = numbers.double(); // 不推薦
const doubled2 = doubleArray(numbers); // 更好的方法
```

```kotlin !! kt
// Kotlin 擴展函數
fun List<Int>.double(): List<Int> {
    return this.map { it * 2 }
}

fun String.reverse(): String {
    return this.reversed()
}

fun Int.isEven(): Boolean {
    return this % 2 == 0
}

// 使用
val numbers = listOf(1, 2, 3)
val doubled = numbers.double()

val text = "hello"
val reversed = text.reverse()

val number = 42
val isEven = number.isEven()
```
</UniversalEditor>

### 帶參數的擴展函數

擴展函數也可以接受參數，使它們更加靈活。

<UniversalEditor title="帶參數的擴展函數" compare={true}>
```javascript !! js
// JavaScript 工具函數
function repeatString(str, times) {
    return str.repeat(times);
}

function padLeft(str, length, char = ' ') {
    return str.padStart(length, char);
}

// 使用
const result1 = repeatString("hello", 3);
const result2 = padLeft("42", 5, '0');
```

```kotlin !! kt
// Kotlin 帶參數的擴展函數
fun String.repeat(times: Int): String {
    return buildString {
        repeat(times) { append(this@repeat) }
    }
}

fun String.padLeft(length: Int, char: Char = ' '): String {
    return this.padStart(length, char)
}

fun List<Int>.filterBy(predicate: (Int) -> Boolean): List<Int> {
    return this.filter(predicate)
}

// 使用
val result1 = "hello".repeat(3)
val result2 = "42".padLeft(5, '0')
val numbers = listOf(1, 2, 3, 4, 5)
val evens = numbers.filterBy { it % 2 == 0 }
```
</UniversalEditor>

## 函數類型和類型別名

### 函數類型聲明

Kotlin 為函數提供了豐富的類型系統，使代碼更具可讀性和類型安全。

<UniversalEditor title="函數類型" compare={true}>
```javascript !! js
// JavaScript - 函數是一等公民但沒有顯式類型
function processNumbers(numbers, processor) {
    return numbers.map(processor);
}

function createAdder(amount) {
    return function(number) {
        return number + amount;
    };
}

// 使用
const numbers = [1, 2, 3];
const addFive = createAdder(5);
const result = processNumbers(numbers, addFive);
```

```kotlin !! kt
// Kotlin 函數類型
fun processNumbers(numbers: List<Int>, processor: (Int) -> Int): List<Int> {
    return numbers.map(processor)
}

fun createAdder(amount: Int): (Int) -> Int {
    return { number -> number + amount }
}

// 複雜函數類型的類型別名
typealias NumberProcessor = (Int) -> Int
typealias StringTransformer = (String) -> String
typealias Predicate<T> = (T) -> Boolean

fun processWithTypeAlias(numbers: List<Int>, processor: NumberProcessor): List<Int> {
    return numbers.map(processor)
}

// 使用
val numbers = listOf(1, 2, 3)
val addFive = createAdder(5)
val result = processNumbers(numbers, addFive)
```
</UniversalEditor>

## 函數式程式設計模式

### 函數組合

函數組合是函數式程式設計中的基本概念，允許您將多個函數組合成單個函數。

<UniversalEditor title="函數組合" compare={true}>
```javascript !! js
// JavaScript 函數組合
const compose = (...fns) => x => fns.reduceRight((acc, fn) => fn(acc), x);
const pipe = (...fns) => x => fns.reduce((acc, fn) => fn(acc), x);

const addOne = x => x + 1;
const multiplyByTwo = x => x * 2;
const square = x => x * x;

const process = compose(square, multiplyByTwo, addOne);
const process2 = pipe(addOne, multiplyByTwo, square);

// 使用
console.log(process(3));  // ((3 + 1) * 2)^2 = 64
console.log(process2(3)); // ((3 + 1) * 2)^2 = 64
```

```kotlin !! kt
// Kotlin 函數組合
fun <T> compose(vararg functions: (T) -> T): (T) -> T = 
    { x -> functions.foldRight(x) { fn, acc -> fn(acc) } }

fun <T> pipe(vararg functions: (T) -> T): (T) -> T = 
    { x -> functions.fold(x) { acc, fn -> fn(acc) } }

val addOne: (Int) -> Int = { it + 1 }
val multiplyByTwo: (Int) -> Int = { it * 2 }
val square: (Int) -> Int = { it * it }

val process = compose(square, multiplyByTwo, addOne)
val process2 = pipe(addOne, multiplyByTwo, square)

// 使用
println(process(3))  // ((3 + 1) * 2)^2 = 64
println(process2(3)) // ((3 + 1) * 2)^2 = 64
```
</UniversalEditor>

### 部分應用和柯里化

部分應用和柯里化是通過固定現有函數的某些參數來創建新函數的技術。

<UniversalEditor title="部分應用和柯里化" compare={true}>
```javascript !! js
// JavaScript 部分應用
function add(a, b) {
    return a + b;
}

function partial(fn, ...args) {
    return function(...moreArgs) {
        return fn.apply(this, args.concat(moreArgs));
    };
}

const addFive = partial(add, 5);
console.log(addFive(3)); // 8

// 柯里化
function curry(fn) {
    return function curried(...args) {
        if (args.length >= fn.length) {
            return fn.apply(this, args);
        }
        return function(...moreArgs) {
            return curried.apply(this, args.concat(moreArgs));
        };
    };
}

const curriedAdd = curry(add);
const addFiveCurried = curriedAdd(5);
console.log(addFiveCurried(3)); // 8
```

```kotlin !! kt
// Kotlin 部分應用和柯里化
fun add(a: Int, b: Int): Int = a + b

// 使用 Lambda 的部分應用
val addFive: (Int) -> Int = { b -> add(5, b) }
println(addFive(3)) // 8

// 柯里化
fun addCurried(a: Int): (Int) -> Int = { b -> a + b }
val addFiveCurried = addCurried(5)
println(addFiveCurried(3)) // 8

// 更複雜的柯里化
fun <A, B, C> ((A, B) -> C).curry(): (A) -> (B) -> C = 
    { a -> { b -> this(a, b) } }

val curriedAdd = ::add.curry()
val addFiveComplex = curriedAdd(5)
println(addFiveComplex(3)) // 8
```
</UniversalEditor>

## 實際示例

### 數據處理管道

讓我們創建一個實際示例，演示函數式程式設計概念在真實場景中的應用。

<UniversalEditor title="數據處理管道" compare={true}>
```javascript !! js
// JavaScript 數據處理管道
const users = [
    { name: "Alice", age: 25, city: "New York" },
    { name: "Bob", age: 30, city: "London" },
    { name: "Charlie", age: 35, city: "Paris" },
    { name: "Diana", age: 28, city: "Tokyo" }
];

// 函數式管道
const result = users
    .filter(user => user.age > 25)
    .map(user => ({
        ...user,
        name: user.name.toUpperCase(),
        ageGroup: user.age > 30 ? 'senior' : 'junior'
    }))
    .sort((a, b) => a.age - b.age)
    .reduce((acc, user) => {
        const group = user.ageGroup;
        if (!acc[group]) acc[group] = [];
        acc[group].push(user);
        return acc;
    }, {});

console.log(result);
```

```kotlin !! kt
// Kotlin 數據處理管道
data class User(
    val name: String,
    val age: Int,
    val city: String
)

val users = listOf(
    User("Alice", 25, "New York"),
    User("Bob", 30, "London"),
    User("Charlie", 35, "Paris"),
    User("Diana", 28, "Tokyo")
)

// 函數式管道
val result = users
    .filter { it.age > 25 }
    .map { user ->
        user.copy(
            name = user.name.uppercase(),
            ageGroup = if (user.age > 30) "senior" else "junior"
        )
    }
    .sortedBy { it.age }
    .groupBy { it.ageGroup }

println(result)
```
</UniversalEditor>

### 函數式程式設計的錯誤處理

函數式程式設計提供了處理錯誤和可選值的優雅方式。

<UniversalEditor title="錯誤處理" compare={true}>
```javascript !! js
// JavaScript 錯誤處理
function divide(a, b) {
    if (b === 0) {
        throw new Error("Division by zero");
    }
    return a / b;
}

function safeDivide(a, b) {
    try {
        return { success: true, result: divide(a, b) };
    } catch (error) {
        return { success: false, error: error.message };
    }
}

// 使用
const result1 = safeDivide(10, 2);
const result2 = safeDivide(10, 0);

console.log(result1); // { success: true, result: 5 }
console.log(result2); // { success: false, error: "Division by zero" }
```

```kotlin !! kt
// Kotlin 使用 Result 的錯誤處理
sealed class Result<out T> {
    data class Success<T>(val value: T) : Result<T>()
    data class Error(val message: String) : Result<Nothing>()
}

fun divide(a: Int, b: Int): Result<Int> {
    return if (b != 0) {
        Result.Success(a / b)
    } else {
        Result.Error("Division by zero")
    }
}

// 使用
val result1 = divide(10, 2)
val result2 = divide(10, 0)

when (result1) {
    is Result.Success -> println("Result: ${result1.value}")
    is Result.Error -> println("Error: ${result1.message}")
}

when (result2) {
    is Result.Success -> println("Result: ${result2.value}")
    is Result.Error -> println("Error: ${result2.message}")
}
```
</UniversalEditor>

## 最佳實踐

### 何時使用函數式程式設計

1. **數據轉換**: 對數據處理管道使用函數式程式設計
2. **不可變數據**: 優先使用不可變集合和數據結構
3. **純函數**: 盡可能編寫無副作用的函數
4. **組合**: 組合小函數創建複雜行為
5. **類型安全**: 利用 Kotlin 的類型系統獲得更好的代碼安全

### 性能考慮

1. **惰性求值**: 對大型集合使用序列
2. **內存使用**: 注意鏈中的中間集合
3. **尾遞歸**: 對遞歸函數使用 tailrec
4. **內聯**: 對性能關鍵代碼使用內聯函數

## 練習題

### 練習 1: 集合操作
創建一個函數，接受數字列表並返回僅包含偶數平方的列表。

<UniversalEditor title="練習 1 解答" compare={true}>
```javascript !! js
// JavaScript 解答
function getEvenSquares(numbers) {
    return numbers
        .filter(num => num % 2 === 0)
        .map(num => num * num);
}

// 使用
const numbers = [1, 2, 3, 4, 5, 6];
const result = getEvenSquares(numbers);
console.log(result); // [4, 16, 36]
```

```kotlin !! kt
// Kotlin 解答
fun getEvenSquares(numbers: List<Int>): List<Int> {
    return numbers
        .filter { it % 2 == 0 }
        .map { it * it }
}

// 使用
val numbers = listOf(1, 2, 3, 4, 5, 6)
val result = getEvenSquares(numbers)
println(result) // [4, 16, 36]
```
</UniversalEditor>

### 練習 2: 擴展函數
為 String 創建一個擴展函數，計算字符串中元音字母的數量。

<UniversalEditor title="練習 2 解答" compare={true}>
```javascript !! js
// JavaScript 解答
String.prototype.countVowels = function() {
    const vowels = 'aeiouAEIOU';
    return this.split('').filter(char => vowels.includes(char)).length;
};

// 使用
const text = "Hello World";
console.log(text.countVowels()); // 3
```

```kotlin !! kt
// Kotlin 解答
fun String.countVowels(): Int {
    val vowels = "aeiouAEIOU"
    return this.count { it in vowels }
}

// 使用
val text = "Hello World"
println(text.countVowels()) // 3
```
</UniversalEditor>

## 總結

在本模組中，我們探索了 Kotlin 強大的函數式程式設計特性：

### 涵蓋的關鍵概念：
- **高階函數**: 接受或返回其他函數的函數
- **Lambda 表達式**: 匿名函數的簡潔語法
- **集合操作符**: 集合上豐富的函數式操作
- **擴展函數**: 向現有類添加新函數
- **函數類型**: 類型安全的函數聲明
- **函數式模式**: 組合、柯里化和部分應用

### Kotlin 函數式程式設計的優勢：
1. **類型安全**: 編譯時類型檢查防止運行時錯誤
2. **空安全**: 內建空安全減少空指針異常
3. **不可變性**: 預設不可變集合
4. **擴展函數**: 無需繼承即可擴展現有類
5. **豐富的標準庫**: 全面的集合操作
6. **互操作性**: 與 Java 庫的無縫集成

### 下一步：
在下一個模組中，我們將探索**協程和異步程式設計**，學習 Kotlin 的協程如何提供比 JavaScript 的 Promise/async-await 模式更優雅的異步程式設計解決方案。

您在這裡學到的函數式程式設計概念將是理解和有效使用協程的基礎，因為它們共享組合和不可變性的相同原則。 